package com.jie.scanbarcode.demo

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Point
import android.os.Bundle
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage
import com.jie.scanbarcode.BarCodeHelper
import com.jie.scanbarcode.PreviewViewTouchListener
import com.jie.scanbarcode.QRCodeAnalysis
import com.jie.scanbarcode.demo.databinding.BarcodeActivityQrCodeScanBinding
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

/**
 * 使用CameraX预览摄像头，并解析二维码
 */
open class QRCodeScanActivity : AppCompatActivity() {

    private var mCamera : Camera? = null
    private var mImageAnalysis : ImageAnalysis? = null
    private lateinit var mViewBinding : BarcodeActivityQrCodeScanBinding
    private val mMainExecutor by lazy { ContextCompat.getMainExecutor(this) }

    /**
     * 图片选择结果回调
     */
    private val mPictureChooseLauncher = registerForActivityResult(ActivityResultContracts.GetContent()){
        it?.let {
            val inputImage : InputImage = InputImage.fromFilePath(this, it)
            BarCodeHelper.process(inputImage, successListener, failureListener)
        }
    }

    /**
     * 权限申请结果回调
     */
    private val mPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
        if (it){ // 权限申请成功
            initEvent()
            startCamera()
        } else { // 缺少摄像头权限
            ToastUtils.showShort("缺少摄像头权限")
            finish()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        fullScreen()
        mViewBinding = BarcodeActivityQrCodeScanBinding.inflate(layoutInflater)
        setContentView(mViewBinding.root)

        // 校验摄像头权限
        if (ContextCompat.checkSelfPermission(this, CAMERA_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
            initEvent()
            startCamera()
        } else {
            mPermissionLauncher.launch(CAMERA_PERMISSION)
        }
    }

    /**
     * 初始化组件的事件
     */
    private fun initEvent() {
        mViewBinding.tvFlushStatus.setOnClickListener {
            controlFlush()
        }
        mViewBinding.ivClose.setOnClickListener {
            finish()
        }
        mViewBinding.ivPhoto.setOnClickListener {
            mPictureChooseLauncher.launch("image/*")
        }
        val previewViewTouchListener = PreviewViewTouchListener(this)
        previewViewTouchListener.setCustomTouchListener(object : PreviewViewTouchListener.CustomTouchListener{

            override fun zoom(delta: Float) {
                mCamera?.cameraInfo?.zoomState?.value?.let {
                    mCamera?.cameraControl?.setZoomRatio(it.zoomRatio * delta)
                }
            }

            override fun click(x: Float, y: Float) {
                // ui上显示对焦点
                mViewBinding.focusView.startFocus(Point(x.toInt(), y.toInt()))
                // 触发对焦操作
                val createPoint = mViewBinding.pvCameraX.meteringPointFactory.createPoint(x, y)
                val focusAction = FocusMeteringAction.Builder(createPoint, FocusMeteringAction.FLAG_AF)
                    .setAutoCancelDuration(3, TimeUnit.SECONDS)
                    .build()
                val startFocusAndMetering = mCamera?.cameraControl?.startFocusAndMetering(focusAction)
                // 设置对焦结果监听
                startFocusAndMetering?.addListener({
                    try {
                        val focusMeteringResult = startFocusAndMetering.get()
                        if (focusMeteringResult.isFocusSuccessful) {
                            mViewBinding.focusView.onFocusSuccess()
                        } else {
                            mViewBinding.focusView.onFocusFailed()
                        }
                    } catch (e : Exception){
                        LogUtils.e(e)
                    }
                }, mMainExecutor)
            }

            override fun doubleClick(x: Float, y: Float) {
                mCamera?.cameraInfo?.zoomState?.value?.let {
                    val zoom = if (it.zoomRatio > it.minZoomRatio){
                        0f
                    } else {
                        0.5f
                    }
                    mCamera?.cameraControl?.setLinearZoom(zoom)
                }
            }

            override fun longClick(x: Float, y: Float) {
            }

        })
        mViewBinding.pvCameraX.setOnTouchListener(previewViewTouchListener)
    }

    /**
     * 开始预览并扫码
     */
    private fun startCamera() {
        val processCameraProvider = getProcessCameraProvider()
        processCameraProvider.addListener({
            // 创建预览
            val preview = Preview.Builder().build()
            // 绑定预览
            preview.setSurfaceProvider(mViewBinding.pvCameraX.surfaceProvider)
            // 图片分析接口
            mImageAnalysis = ImageAnalysis.Builder()
                    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                    .build()
            addImageAnalyzer()
            // 使用后置摄像头
            val cameraSelector = CameraSelector.Builder()
                    .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                    .build()
            processCameraProvider.get().also {
                // 先解绑之前的
                it.unbindAll()
                // 重新绑定
                mCamera = it.bindToLifecycle(this, cameraSelector, preview, mImageAnalysis)
            }
        }, mMainExecutor)
    }

    /**
     * 添加图片分享回调
     */
    private fun addImageAnalyzer() {
        // 图片分析回调
        val qrCodeAnalysis = QRCodeAnalysis(successListener, failureListener)
        mImageAnalysis?.setAnalyzer(Executors.newSingleThreadExecutor(), qrCodeAnalysis)
    }

    private fun getProcessCameraProvider() = ProcessCameraProvider.getInstance(this)

    /**
     * 控制闪光灯的开启、关闭
     */
    private fun controlFlush(){
        val cameraControl = mCamera?.cameraControl
        // 获取闪光灯的开启/关闭状态
        val status = mCamera?.cameraInfo?.torchState?.value
        val open = status == TorchState.ON
        // 若闪关灯开启，则关闭；若闪关灯关闭，则开启
        cameraControl?.enableTorch(!open)
        setFlushStatus(!open)
    }

    /**
     * 设置闪光灯的打开和关闭状态
     * @param open true:打开状态 false:关闭状态
     */
    private fun setFlushStatus(open: Boolean){
        mViewBinding.tvFlushStatus.run {
            if (visibility == View.VISIBLE){
                isSelected = open
                setText(if (!open) R.string.code_flush_off else R.string.code_flush_on)
            }
        }
    }

    override fun onStop() {
        super.onStop()
        // 当不可见时，将闪光灯状态组件置为关闭状态
        setFlushStatus(false)
    }

    /**
     * 扫描成功回调
     */
    private val successListener: (Barcode, Int, Int) -> Unit = { barcode, width, height ->
        // FIXME: 2021/5/28 这里如果移除了摄像头，则屏幕停止不动，也不能再次触发扫描了
        // 移除所有摄像头操作
//        getProcessCameraProvider().get().unbindAll()
        mImageAnalysis?.clearAnalyzer()
        val result = "value: ${barcode.rawValue} type:${barcode.valueType} width:$width height:$height"
        LogUtils.i(result)
//        Toast.makeText(this, result, Toast.LENGTH_SHORT).show()
        QRCodeResultDialog().run {
            resultStr = barcode.rawValue
            againstListener = {
                addImageAnalyzer()
            }
            exitListener = {
                finish()
            }
            show(supportFragmentManager, this.toString())
        }
    }

    /**
     * 扫描失败回调
     */
    private val failureListener: (Exception) -> Unit = {
        LogUtils.i("startCamera: ", it)
        ToastUtils.showShort("解析出错了")
    }

    companion object {
        // 摄像头权限
        private const val CAMERA_PERMISSION = Manifest.permission.CAMERA
    }
}